<template>
  <div class="department-select-input">
    <!--    部门输入框，获得焦点时弹出部门选择弹窗-->
    <el-input
      placeholder="请选择部门"
      @focus="isDepartmentDialogVisible = true"
      :value="selectedDeptName"
      clearable
      @clear="clear"
    />
    <!--    部门弹窗-->
    <el-dialog
      title="选择部门"
      width="500px"
      :visible.sync="isDepartmentDialogVisible"
      append-to-body
      :close-on-click-modal="false"
    >
      <!--      部门table列表-->
      <el-table height="480" :data="departmentTree" row-key="id">
        <el-table-column label="部门名称" prop="deptName" />
        <el-table-column label="选择">
          <template slot-scope="scope">
            <el-button type="text" @click="onSelectDept(scope.row)">选择</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!--      弹窗底部关闭按钮-->
      <div slot="footer">
        <el-button @click="isDepartmentDialogVisible = false">取消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { actions as deptActions } from '@/store/modules/account/department';
import { mapState, mapActions } from 'vuex';

const deptStoreNamespace = 'account/department';

/**
 * 该组件渲染了选择部门的Input输入框，点击input的时候
 * 会弹出部门选择的对话框，选择部门后，input中会显示选择的部门名称
 */
export default {
  name: 'DepartmentSelectInput',
  props: {
    // 传入选中的部门的id
    value: {
      type: [String, Number],
      default: '',
    },
  },
  data() {
    return {
      // 选中的部门名称，在input中展示
      selectedDeptName: '',
      // 是否弹出部门选择的对话框
      isDepartmentDialogVisible: false,
    };
  },
  mounted() {
    // mounted时加载部门树
    // 使用这种写法是为了避免value的值改变时，重复调用远程接口
    // 原理是标记为resolved的promise不会重复执行
    this.fetchDeptPromise = this.getDepartmentTree().then(() => {
      if (this.value) {
        this.setDepartmentName(this.value);
      }
    });
  },
  computed: {
    ...mapState(deptStoreNamespace, {
      departmentTree: state => state.departmentTree,
    }),
  },
  watch: {
    /**
     * 如果value的值改变了，那么重新加载部门名称
     */
    value(deptId) {
      this.fetchDeptPromise.then(() => {
        this.setDepartmentName(deptId);
      });
    },
  },
  methods: {
    ...mapActions(deptStoreNamespace, {
      getDepartmentTree: deptActions.GET_DEPARTMENT_TREE,
    }),
    /**
     * 对话框选中后，会抛出一个input事件
     */
    onSelectDept(dept) {
      this.selectedDeptName = dept.deptName;
      this.$emit('input', dept.id);
      this.$emit('change');
      this.$emit('changeItem', dept);
      this.isDepartmentDialogVisible = false;
    },
    /**
     * 清空部门选择
     */
    clear() {
      this.$emit('input', '');
      this.$emit('change');
    },
    /**
     * 使用部门id，构建出要显示的部门名称
     * 会一并显示其父部门，部门间使用连字符连接
     * 如 部门1-子部门1.1-子部门1.1.2
     */
    setDepartmentName(deptId) {
      let dept = this.getDeptChainById(this.departmentTree, deptId);

      let deptName = '';
      while (dept) {
        deptName += `${dept.deptName}-`;
        dept = dept.next;
      }
      this.selectedDeptName = deptName.substring(0, deptName.length - 1);
    },
    /**
     * 构建一个从顶级到要寻找的dept的链, 顶级部门通过next字段可以找到下级部门，直到部门deptId与参数的deptId相同
     * a.next -> b.next -> null
     *
     * @param {Array} deptList 部门列表
     * @param {number} deptId 要查找的部门ID
     * @return {{ next: {}| null }| null} 返回顶级的部门类
     */
    getDeptChainById(deptList, deptId) {
      // 判断depList，若为空变量或者长度为0，返回undefined
      if (!deptList || deptList.length === 0) {
        return undefined;
      }
      // 判断通过，执行以下代码
      for (const deptItem of deptList) {
        if (Number(deptItem.id) === Number(deptId)) {
          return {
            ...deptItem,
            next: null,
          };
        }
        const children = this.getDeptChainById(deptItem.children, deptId);
        if (children) {
          return {
            ...deptItem,
            next: children,
          };
        }
      }
      return null;
    },
  },
};
</script>

<style lang="scss">
.department-select-input {
  display: inline-block;
  width: 100%;
}
</style>
